package cn.ibizlab.core.authentication.aspect;

import cn.ibizlab.core.authentication.domain.AuthLogin;
import cn.ibizlab.core.authentication.service.impl.AuthenticationService;
import cn.ibizlab.util.enums.Entities;
import cn.ibizlab.util.errors.BadRequestAlertException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.Arrays;

/**
 * 图片验证码校验切面类：校验用户输入的验证码是否正确
 */
@Aspect
@Component
@Order(100)
@ConditionalOnExpression("'${ibiz.auth.imageCaptcha.enable:false}'.equals('true')")
public class SysAuthCaptchaAspect{

    @Autowired
    AuthenticationService authenticationService;
    @Value("${ibiz.auth.imageCaptcha.whitelist:aibizhi}")
    private String whitelist;

    /**
     * 用户登录和发送短信前需要校验验证码
     * @param point
     * @return
     * @throws Throwable
     */
    @Around(value ="execution(* cn.ibizlab.core.authentication.service.AuthLoginService.login(..)) || execution(* cn.ibizlab.core.authentication.service.AuthLoginService.sendSmsCode(..))")
    public Object execute(ProceedingJoinPoint point) throws Throwable{
        Object result;
        String imageCaptchaCode;
        String imageCaptchaId = null;
        String imageCaptcha = null;
        try{
            Object[] args = point.getArgs();
            if(!ObjectUtils.isEmpty(args) && args[0] instanceof AuthLogin && !isWhitelist((AuthLogin) args[0])){
                AuthLogin authLogin = (AuthLogin) args[0];
                imageCaptchaId = authLogin.getState();
                imageCaptchaCode = authLogin.getCode();
                if(!ObjectUtils.isEmpty(imageCaptchaId) && !ObjectUtils.isEmpty(imageCaptchaCode)){
                    //1.验证code有效性（是否为jwt格式，token是否过期）
                    boolean validResult = authenticationService.validateTokenByRSA(imageCaptchaId);
                    if (!validResult)
                        throw new BadRequestAlertException("验证码已失效", Entities.AUTH_LOGIN.toString(),"The verification code has expired");

                    //2.验证用户输入的验证码是否与缓存中的验证码一致
                    imageCaptcha = authenticationService.getImageCaptcha(imageCaptchaId);
                    if(ObjectUtils.isEmpty(imageCaptcha))
                        throw new BadRequestAlertException("验证码已失效", Entities.AUTH_LOGIN.toString(),"The verification code has expired");

                    if(!imageCaptcha.equals(imageCaptchaCode)){
                        throw new BadRequestAlertException("验证码有误，请重新输入", Entities.AUTH_LOGIN.toString(),"Error in verification code");
                    }
                }
            }
            //执行用户登录逻辑
            result = point.proceed();
        }finally {
            //3.登录之后，清除缓存中验证码，避免使用同一套验证码重复登录
            if(imageCaptcha != null && !ObjectUtils.isEmpty(imageCaptchaId))
                authenticationService.resetImageCaptcha(imageCaptchaId);
        }
        return result;
    }

    /**
     * 验证码白名单：在白名单内的用户，登录时不校验图片验证码
     * @return
     */
    protected boolean isWhitelist(AuthLogin authLogin){
        String loginName = authLogin.getLoginName();
        if(!ObjectUtils.isEmpty(loginName) && !ObjectUtils.isEmpty(whitelist) && Arrays.asList(whitelist.split(",|;")).contains(loginName))
            return true;
        else
            return false;
    }

}
